﻿<template>
  <div class="signature-pad-container">
    <!-- 按钮区域 -->
    <div class="signature-btns">
      <el-button @click="handleClear">重写</el-button>
      <el-button type="primary" @click="handleSave">确定</el-button>
      <el-button @click="closeDialog">取消</el-button>
    </div>

    <!-- 签名区域 -->
    <div
      :class="{ 'has-signature': hasSignature }"
      :style="{ width: width + 'px', height: height + 'px' }"
      class="signature-area"
    >
      <!-- 背景层 canvas 用于绘制田字格 -->
      <canvas
        ref="gridCanvasRef"
        :height="height"
        :style="{ width: width + 'px', height: height + 'px' }"
        :width="width"
        class="grid-canvas"
      ></canvas>
      <!-- 签名层 canvas -->
      <canvas
        ref="canvasRef"
        :height="height"
        :style="{ width: width + 'px', height: height + 'px' }"
        :width="width"
        class="signature-canvas"
      ></canvas>
    </div>
  </div>
</template>

<script lang="ts" setup>
import { defineEmits, defineExpose, defineProps, nextTick, onMounted, ref, watch } from 'vue'
import SignaturePad from 'signature_pad'
import { ElMessage } from 'element-plus'
import * as UserApi from '@/api/system/user'

/**
 * 定义组件接收的属性
 */
const props = defineProps({
  modelValue: String, // base64 格式的签名数据
  nickname: String, // 用户昵称（用于提取中文字符）
  taskId: String, // taskId
  tenantId: String, // taskId
  expireDate: String, //  签名过期时间
  title: String // 显示标题
})

/**
 * 定义组件触发的事件
 */
const emit = defineEmits(['update:modelValue', 'save', 'closeDialog'])

/**
 * 引用签名画布元素
 */
const canvasRef = ref<HTMLCanvasElement | null>(null)

/**
 * 引用背景网格画布元素
 */
const gridCanvasRef = ref<HTMLCanvasElement | null>(null)

/**
 * 是否已有签名标志位
 */
const hasSignature = ref(false)

/**
 * 签名板实例对象
 */
let signaturePad: SignaturePad | null = null

/**
 * 关闭对话框方法
 */
const closeDialog = () => {
  emit('closeDialog')
}

/**
 * 签名区域宽度
 */
const width = ref(0)

/**
 * 签名区域高度
 */
const height = ref(0)

/**
 * 获取屏幕尺寸信息并设置签名区域大小
 */
const getScreenInfo = () => {
  height.value = window.innerHeight * 0.99
  width.value = window.innerWidth * 0.8
}

/**
 * 提取字符串中的中文字符数组
 * @param text 输入文本
 * @returns 匹配到的所有中文字符组成的数组
 */
const getChineseChars = (text: string): string[] => {
  if (!text) return []
  // 正则匹配所有中文字符
  const chineseRegex = /[\u4e00-\u9fa5]/g
  const matches = text.match(chineseRegex)
  return matches || []
}

/**
 * 组件挂载后初始化签名面板及背景网格
 */
onMounted(() => {
  getScreenInfo()
  nextTick(() => {
    // 绘制田字格背景
    drawGridVertical()

    if (canvasRef.value) {
      signaturePad = new SignaturePad(canvasRef.value, {
        minWidth: 1,       // 最细笔触（比原来更细，扩大粗细范围）
        maxWidth: 10,       // 最粗笔触（保持适中，避免过于臃肿）
        velocityFilterWeight: 0.5,  // 速度过滤权重（降低值，让粗细变化更灵敏）
        penColor: '#1a1a1a',        // 稍深的颜色，增强手写质感
        throttle: 16,      // 绘制频率（16ms≈60帧，更流畅）
        minDistance: 5     // 最小绘制距离（避免点过于密集）
      });
      // 监听开始签名事件更新状态
      signaturePad.addEventListener('beginStroke', () => {
        hasSignature.value = true
      })

      // 回显已有的签名数据
      if (props.modelValue) {
        signaturePad.fromDataURL(props.modelValue)
        hasSignature.value = !signaturePad.isEmpty()
      }
    }
  })
})

/**
 * 监听 modelValue 变化以同步外部传入的数据
 */
watch(
  () => props.modelValue,
  (val) => {
    if (signaturePad) {
      signaturePad.clear()
      if (val) {
        signaturePad.fromDataURL(val)
        hasSignature.value = !signaturePad.isEmpty()
      } else {
        hasSignature.value = false
      }
    }
  },
  { immediate: true }
)

/**
 * 监听 nickname 的变化重新绘制田字格
 */
watch(
  () => props.nickname,
  () => {
    nextTick(() => {
      drawGridVertical()
    })
  },
  { immediate: false }
)

/**
 * 清除当前签名内容
 */
function handleClear() {
  if (signaturePad) {
    signaturePad.clear()
    hasSignature.value = false
  }
}

/**
 * 【修改点 1】处理保存签名操作
 * 调用一个新函数 rotateSignatureOnly 来只导出签名
 */
function handleSave() {
  if (!signaturePad) return
  if (signaturePad.isEmpty()) {
    ElMessage.error('请先签名')
    return
  }
  // 将签名旋转并导出（不包含网格）
  const rotatedSignature = rotateSignatureOnly()

  UserApi.updateSignTask({
    taskId: props.taskId,
    sign: rotatedSignature
  })
  emit('closeDialog')
  ElMessage.warning('签字完成')
}

/**
 * 绘制竖向堆叠的田字格（导出时旋转为横向效果）
 */
const drawGridVertical = async () => {
  if (!gridCanvasRef.value) return
  const canvas = gridCanvasRef.value
  const ctx = canvas.getContext('2d')
  if (!ctx) return

  ctx.clearRect(0, 0, canvas.width, canvas.height)

  const chineseChars = getChineseChars(props.nickname || '')
  const chineseCount = chineseChars.length
  if (chineseCount === 0) return

  const paddingX = 10
  const topPadding = 10
  const bottomPadding = 10
  const gridSpacing = 5
  const availableWidth = width.value - paddingX * 2
  const availableHeight = height.value - topPadding - bottomPadding

  const maxHeightPerCell = (availableHeight - gridSpacing * (chineseCount - 1)) / chineseCount
  const cellSize = Math.min(availableWidth, maxHeightPerCell)

  const startX = paddingX + (availableWidth - cellSize) / 2
  const totalGridHeight = cellSize * chineseCount + gridSpacing * (chineseCount - 1)
  const firstY = topPadding + (availableHeight - totalGridHeight) / 2

  // 在绘制前，先等待自定义字体加载完成
  try {
    const font = `${cellSize}px MyKaiti`
    await document.fonts.load(font)
  } catch (err) {
    console.error('MyKaiti 字体加载失败，将使用后备字体:', err)
  }

  // 字体加载完成后再执行绘制循环
  for (let i = 0; i < chineseCount; i++) {
    const x = startX
    const y = firstY + i * (cellSize + gridSpacing)
    const char = chineseChars[i]

    // 绘制田字格
    ctx.save()
    ctx.strokeStyle = '#cccccc'
    ctx.lineWidth = 1
    ctx.setLineDash([4, 4])
    ctx.strokeRect(x, y, cellSize, cellSize)
    ctx.beginPath()
    ctx.moveTo(x, y + cellSize / 2)
    ctx.lineTo(x + cellSize, y + cellSize / 2)
    ctx.stroke()
    ctx.beginPath()
    ctx.moveTo(x + cellSize / 2, y)
    ctx.lineTo(x + cellSize / 2, y + cellSize)
    ctx.stroke()
    ctx.restore()

    // 绘制半透明的实心背景文字
    ctx.save()
    ctx.fillStyle = '#000000'
    ctx.font = `${cellSize}px "MyKaiti", "KaiTi", "KaiTi_GB2312", "STKaiti", "STKaiTi", "SimKai", serif`
    ctx.textAlign = 'center'
    ctx.textBaseline = 'middle'
    ctx.globalAlpha = 0.2
    ctx.translate(x + cellSize / 2, y + cellSize / 2)
    ctx.rotate(Math.PI / 2)
    ctx.fillText(char, 0, 0)
    ctx.restore()
  }
}

/**
 * 【修改点 2】新增函数：仅旋转并导出签名
 * @returns 旋转后的 base64 图片数据
 */
function rotateSignatureOnly(): string {
  const sigCanvas = canvasRef.value as HTMLCanvasElement
  if (!sigCanvas) return ''

  const w = sigCanvas.width
  const h = sigCanvas.height

  // 创建一个新的离屏 canvas 用于旋转
  const offscreenCanvas = document.createElement('canvas')
  offscreenCanvas.width = h // 旋转后宽度是原始高度
  offscreenCanvas.height = w // 旋转后高度是原始宽度

  const ctx = offscreenCanvas.getContext('2d')
  if (!ctx) return sigCanvas.toDataURL('image/png') // 异常情况返回原始图像

  // 将坐标系原点移动到左下角，然后进行逆时针旋转 90 度
  ctx.translate(0, offscreenCanvas.height)
  ctx.rotate(-Math.PI / 2)

  // 只绘制签名层的 canvas
  ctx.drawImage(sigCanvas, 0, 0)

  return offscreenCanvas.toDataURL('image/png')
}

/**
 * 允许父组件调用清除功能
 */
defineExpose({
  clear: handleClear
})
</script>

<!-- 全局样式：用于定义 @font-face -->
<style>
@font-face {
  font-family: 'MyKaiti';
  src: url('./KaiTi_GB2312.woff2') format('woff2');
  font-display: swap;
}
</style>

<!-- 组件作用域样式 -->
<style scoped>
/* ==================== 最终样式修正 START ==================== */

/* 整体容器：左右布局，垂直居中 */
.signature-pad-container {
  display: flex;
  flex-direction: row;
  align-items: center;
  font-family: 'MyKaiti', 'KaiTi', 'KaiTi_GB2312', 'STKaiti', 'STKaiTi', 'SimKai', serif;
}

/* 按钮组容器：垂直堆叠按钮 */
.signature-btns {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 100px;
}

/* 单个按钮样式：旋转并调整尺寸 */
.signature-btns .el-button {
  width: 80px; /* <<<< 微调按钮尺寸 */
  margin: 0 !important;
  padding: 0;
  transform: rotate(90deg);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 18px;
}

/* 签名区域样式 */
.signature-area {
  border: 1.5px solid #e4e7ed;
  border-radius: 12px;
  background: #f7f8fa;
  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.06);
  display: flex;
  justify-content: center;
  align-items: center;
  transition: border-color 0.2s;
  position: relative;
}

.signature-area:hover {
  border-color: #409eff;
}

/* 背景网格 Canvas */
.grid-canvas {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 0;
  pointer-events: none;
}

/* 签名层 Canvas */
.signature-canvas {
  position: relative;
  z-index: 1;
}

/* 当有签名时，隐藏提示文字 */
.signature-area.has-signature::after {
  display: none;
}
</style>
